import { NextRequest, NextResponse } from 'next/server';
import { matchWish, WishRecord } from '@/lib/wishes';
import { getUserIdFromAuthHeader } from '@/lib/auth';

export const dynamic = 'force-dynamic';

interface GraphNode {
    id: string;
    group: 'wish' | 'user';
    label: string;
    data?: any;
    level?: number;
}

interface GraphLink {
    source: string;
    target: string;
    type: 'achieved' | 'desires';
}

export async function GET(request: NextRequest) {
    const searchParams = request.nextUrl.searchParams;
    const centerIdParam = searchParams.get('centerId');
    const depthParam = searchParams.get('depth');

    // For the initial call, we might need a userId to exclude self, 
    // but for graph exploration, we might just want connections.
    // However, matchWish requires a userId to exclude. 
    // We can try to get it from auth, or use a dummy if public (though matchWish logic implies exclusion).
    const currentUserId = getUserIdFromAuthHeader(request) || 0;

    if (!centerIdParam) {
        return NextResponse.json({ error: 'centerId is required' }, { status: 400 });
    }

    const centerWishId = parseInt(centerIdParam);
    const maxDepth = Math.min(Math.max(parseInt(depthParam || '1'), 1), 5);

    const nodes = new Map<string, GraphNode>();
    const links = new Set<string>(); // "source-target" string to dedup
    const linkObjects: GraphLink[] = [];

    // Queue: [WishId, UserIdWhoWantsIt, CurrentDepth]
    // We need UserIdWhoWantsIt to call matchWish correctly (to exclude them).
    const queue: { wishId: number; userId: number; depth: number }[] = [
        { wishId: centerWishId, userId: currentUserId, depth: 0 }
    ];

    const visitedWishes = new Set<number>();
    visitedWishes.add(centerWishId);

    // Add Center Node (Placeholder, we might not have its details yet unless we fetch it, 
    // but usually the frontend has it. We'll add a skeleton or fetch it if needed.
    // For now, let's assume the frontend passes details or we fetch. 
    // To keep it simple, we'll add it when we process connections or just return structure.)
    nodes.set(`w-${centerWishId}`, {
        id: `w-${centerWishId}`,
        group: 'wish',
        label: 'Center Wish', // Ideally fetch content
        level: 0
    });

    while (queue.length > 0) {
        const { wishId, userId, depth } = queue.shift()!;

        if (depth >= maxDepth) continue;

        // Find who achieved this wish
        const matches = await matchWish(userId, wishId);

        for (const match of matches) {
            const matchUserNodeId = `u-${match.matchedUserId}`;

            // Add User Node
            if (!nodes.has(matchUserNodeId)) {
                nodes.set(matchUserNodeId, {
                    id: matchUserNodeId,
                    group: 'user',
                    label: match.username,
                    level: depth + 1
                });
            }

            // Link: User Achieved Wish (User -> Wish) or (Wish <- User)?
            // Logic: Center Wish (Desired) <--- User (Achieved)
            // Let's make arrows flow from Achiever to Desirer? 
            // Or just connections. Let's say: User --achieved--> Wish
            const linkKey1 = `${matchUserNodeId}-w-${wishId}`;
            if (!links.has(linkKey1)) {
                links.add(linkKey1);
                linkObjects.push({ source: matchUserNodeId, target: `w-${wishId}`, type: 'achieved' });
            }

            // Now process this user's desired wishes
            for (const desired of match.desiredWishes) {
                const desiredWishNodeId = `w-${desired.id}`;

                // Add Wish Node
                if (!nodes.has(desiredWishNodeId)) {
                    nodes.set(desiredWishNodeId, {
                        id: desiredWishNodeId,
                        group: 'wish',
                        label: desired.content,
                        data: desired,
                        level: depth + 2
                    });
                }

                // Link: User --desires--> Wish
                const linkKey2 = `${matchUserNodeId}-${desiredWishNodeId}`;
                if (!links.has(linkKey2)) {
                    links.add(linkKey2);
                    linkObjects.push({ source: matchUserNodeId, target: desiredWishNodeId, type: 'desires' });
                }

                // Enqueue this wish to find who achieved IT
                if (!visitedWishes.has(desired.id)) {
                    visitedWishes.add(desired.id);
                    queue.push({ wishId: desired.id, userId: match.matchedUserId, depth: depth + 1 });
                }
            }
        }
    }

    return NextResponse.json({
        nodes: Array.from(nodes.values()),
        links: linkObjects
    });
}
